/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or ( at your option ) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
aLONG with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

/**
 * Local Includes:
 **/
#include "commonheaders.h"
#include "ctrl.h"

/**
 * Macros:
 **/

LPTSTR EscapesToMultiline( LPTSTR str )
{  //converts "\\n" and "\\t" to "\r\n" and "\t" because a multi-line edit box can show them properly
	static const TCHAR escapes[]={
		'a','\a',
		'b','\b',
		'e',27,
		'f','\f',
		'r','\r',
		't','\t',
		'v','\v',
		'\\','\\'
	};

	DWORD i, cchStr = _tcslen( str );
	SHORT wExtra = 0;
	LPTSTR ptr;

	if( !str ) return NULL;

	for( ptr = str; *ptr; ptr++ ) {
		switch( *ptr ) {
			// unix linefeed -> windows linefeed
			case '\n':
				if( ptr == str || *( ptr - 1 ) != '\r' ) {
					if( wExtra <= 0 ) {
						i = ptr - str;
						wExtra = 8;
						if( !( str = ( LPTSTR )mir_realloc( str, ( cchStr + wExtra + 1 ) * sizeof( TCHAR ) ) ) )
							return NULL;
						cchStr += wExtra;
						ptr = str + i;
						str[cchStr] = 0;
					}
					memmove( ptr + 1, ptr, ( cchStr - ( ptr - str ) - 1 ) * sizeof( TCHAR ) );
					wExtra--;
					*ptr = '\r';
				}
				break;
			// mac linefeed -> windows linefeed
			case '\r':
				if( *( ptr + 1 ) != '\n' ) {
					if( wExtra <= 0 ) {
						i = ptr - str;
						wExtra = 8;
						if( !( str = ( LPTSTR )mir_realloc( str, ( cchStr + wExtra + 1 ) * sizeof( TCHAR ) ) ) )
							return NULL;
						cchStr += wExtra;
						ptr = str + i;
						str[cchStr] = 0;
					}
					memmove( ptr + 2, ptr + 1, ( cchStr - ( ptr - str ) - 2 ) * sizeof( TCHAR ) );
					wExtra--;
					ptr[1] = '\n';
				}
				break;
			// escapes -> windows linefeed
			case '\\':
				if( *( ptr + 1 ) == 'n' ) {
					*ptr++ = '\r';
					*ptr = '\n';
				}
				else 
				if( *( ptr + 1 ) == 't' ) {
					*ptr = '\t';
					memmove( ptr + 1, ptr + 2, ( cchStr - ( ptr - str ) - 1 ) * sizeof( TCHAR ) );
					wExtra++;
				}
				break;
		}
	}
	return str;
}


/**
 * name:	Edit_Init
 * desc:	allocates the memory for an edit control's info structure if not done yet
 * param:	hEdit - windowhandle to control
 * return:	the info structure
 **/
LPECTRL	Edit_Init( HANDLE hContact, HWND hEdit )
{
	LPECTRL peCtrl = NULL;

	// allocate edit control's infostructure
	if( hEdit && !PtrIsValid( peCtrl = ( LPECTRL )GetUserData( hEdit ) ) ) {
		HANDLE hContact = INVALID_HANDLE_VALUE;

		if( !( peCtrl = ( LPECTRL )mir_alloc( sizeof( ECTRL ) ) ) )
			return DBVT_DELETED;
		peCtrl->nType = CTRL_EDIT;
		peCtrl->wFlags = 0;
		SetUserData( hEdit, peCtrl );
		if( !hContact ) Edit_LimitText( hEdit, 1024 );
	}
	return peCtrl;
}

/**
 * name:	Edit_SetValue
 * desc:	read a setting from database and set its value to the edit control
 * param:	hDlg	  - owning dialog box of edit control
 *			idEdit	  - edit controls identifier
 *			hContact  - handle to get setting from
 *			szModule  - module or NULL for base protocol to get the setting from
 *			szSetting - the setting to read
 *
 * return:	state of edit control ( changed or unchanged )
 **/
BYTE Edit_SetValue( HWND hDlg, INT idEdit, HANDLE hContact, LPCSTR szModule, LPCSTR szBaseProto, LPCSTR szSetting )
{
	HWND hEdit = GetDlgItem( hDlg, idEdit );
	LPECTRL peCtrl = Edit_Init( hContact, hEdit );
	DBVARIANT dbv;
	LPCSTR szSubMod;

	if( !peCtrl ) return 0;

	if( peCtrl->wFlags & CTRLF_CHANGED )
		return CTRLF_CHANGED;

	if( !szModule ) szSubMod = USERINFO;
	else szSubMod = szModule;

	// read setting from contact's basic protocol
	peCtrl->wFlags &= ~( CTRLF_HASCUSTOM|CTRLF_HASPROTO|CTRLF_HASMETA );
	peCtrl->wFlags |= DB::Setting::GetTStringCtrl( hContact, szModule, szSubMod, szBaseProto, szSetting, &dbv );
	
	EnableWindow( hEdit, 
		!hContact ||
		( peCtrl->wFlags & CTRLF_HASCUSTOM ) || 
		!( peCtrl->wFlags & ( CTRLF_HASPROTO|CTRLF_HASMETA ) ) ||
		!DB::Setting::GetByte( SET_PROPSHEET_PCBIREADONLY, 0 ) );

	peCtrl->valueType = dbv.type;
	switch( dbv.type ) {
		case DBVT_BYTE:
			SetDlgItemInt( hDlg, idEdit, dbv.bVal, FALSE );
			break;

		case DBVT_WORD:
			SetDlgItemInt( hDlg, idEdit, dbv.wVal, FALSE );
			break;

		case DBVT_DWORD:
			SetDlgItemInt( hDlg, idEdit, dbv.dVal, FALSE );
			break;

		case DBVT_TCHAR:
			if( dbv.ptszVal ) {
				SetWindowText( hEdit, dbv.ptszVal );
				break;
			}
		default:
			SetWindowText( hEdit, _T( "" ) );
			break;
	}
	// changed flag may have been set by some message handler, so delete it
	peCtrl->wFlags &= ~CTRLF_CHANGED;
	DB::Variant::Free( &dbv );
	return 0;
}

/**
 * name:	Edit_WriteValue
 * desc:	get value from edit control and write a setting to database
 * param:	hDlg		- owning dialog box of edit control
 *			idEdit		- edit controls identifier
 *			hContact	- handle to get setting from
 *			szModule	- module or NULL for base protocol to get the setting from
 *			szBaseProto - basic protocol for user
 *			szSetting	- the setting to read
 *
 * return 1 on failure 0 on success
 **/
BYTE Edit_WriteValue( HWND hDlg, INT idEdit, HANDLE hContact, LPCSTR szModule, LPCSTR szBaseProto, LPCSTR szSetting, BYTE bType )
{
	HWND hEdit = GetDlgItem( hDlg, idEdit );
	if( hEdit ) {

		LPECTRL peCtrl = ( LPECTRL )GetUserData( hEdit );
		if( PtrIsValid( peCtrl ) && peCtrl->nType == CTRL_EDIT ) {
	
			if( peCtrl->wFlags & CTRLF_CHANGED ) {
				DWORD cch = GetWindowTextLength( hEdit );
	
				if( !hContact ) szModule = szBaseProto;

				if( cch > 0 && ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ) {
					BOOLEAN		need_free = 0;
					LPTSTR		val;
				
					__try {
						val = ( LPTSTR )alloca( ( cch + 1 ) * sizeof( TCHAR ) );
					}
					 __except(GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION ? 
								 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
						val = ( LPTSTR )mir_alloc( ( cch + 1 ) * sizeof( TCHAR ) );
						need_free = 1;
					}

					if( GetWindowText( hEdit, val, cch + 1 ) > 0 ) {
						switch( bType ) {
							case DBVT_BYTE:
								if( DB::Setting::WriteByte( hContact, szModule, szSetting, ( BYTE )_tcstol( val, NULL, 10 ) ) )
									return 0;
								break;
							case DBVT_WORD:
								if( DB::Setting::WriteWord( hContact, szModule, szSetting, ( WORD )_tcstol( val, NULL, 10 ) ) )
									return 0;
								break;
							case DBVT_DWORD:
								if( DB::Setting::WriteDWord( hContact, szModule, szSetting, ( DWORD )_tcstol( val, NULL, 10 ) ) )
									return 0;
								break;
							default:
								if( DB::Setting::WriteTString( hContact, szModule, szSetting, val ) )
									return 0;
								break;
						}
						if( !hContact ) {
							peCtrl->wFlags &= ~CTRLF_HASCUSTOM;
							peCtrl->wFlags |= CTRLF_HASPROTO;
						}
					}
					if( need_free ) {
						mir_free( val );
					}
				}
				else {
					DB::Setting::Delete( hContact, szModule, szSetting );
					peCtrl->wFlags &= ~CTRLF_HASCUSTOM;
				}			
				peCtrl->wFlags &= ~CTRLF_CHANGED;
				InvalidateRect( hEdit, NULL, TRUE );
	}	}	}
	return bType;
}

/**
 * name:	Edit_ChangedLargeString
 * desc:	set changed flag for edit control and current propertysheetpage
 * param:	hDlg	- owning propertysheetpage dialog
 *			idEdit	- control identifier for the editbox
 *
 * return	nothing
 **/
VOID Edit_Changed( HWND hDlg, INT idEdit, LPCSTR szModule, LPCSTR szSetting )
{
	// dialog is locked, or invalid protocol? return
	if( !PspIsLocked( hDlg ) ) {

		HWND hEdit = GetDlgItem( hDlg, idEdit );
		if( hEdit != NULL ) {
			
			LPECTRL peCtrl = ( LPECTRL )GetUserData( hEdit );
			if( PtrIsValid( peCtrl ) && peCtrl->nType == CTRL_EDIT ) {
				HANDLE		hContact;
				INT				cch = GetWindowTextLength( hEdit );
				
				if( !PSGetContact( hDlg, hContact ) )
					hContact = NULL;

				if( !( peCtrl->wFlags & CTRLF_CHANGED ) || ( hContact && cch == 0 && ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ) ) {
					LPCSTR		szBaseProto;
					DBVARIANT dbv;
					INT				rc;
					BOOLEAN		bChanged = FALSE;
					
					if( !PSGetBaseProto( hDlg, szBaseProto ) )
						szBaseProto = NULL;
				
					// read value from db
					rc = ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ? DB::Setting::GetTString( hContact, szModule, szSetting, &dbv ) : 1;
					if( rc ) rc = DB::Setting::GetTString( hContact, szBaseProto, szSetting, &dbv );

					// Value does not exist in database but edit control contains any value.
					if( ( rc || dbv.type == DBVT_DELETED ) && cch > 0 ) {
						bChanged = TRUE;
					}
					// Value exists in database but edit control contains no value.
					else if( !cch ) {
						switch( dbv.type ) {
							case DBVT_BYTE:	case DBVT_WORD:	case DBVT_DWORD:
								bChanged = TRUE;
								break;

							case DBVT_TCHAR:
								bChanged = dbv.ptszVal[0] != 0;
								break;
						}
					}
					// Both database and edit control contain values which need to be compared.
					else {
						BOOLEAN		need_free = 0;
						LPTSTR		val;
					
						__try {
							val = ( LPTSTR )alloca( ( cch + 1 ) * sizeof( TCHAR ) );
						}
						__except(GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION ? 
								 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
							val = ( LPTSTR )mir_alloc( ( cch + 1 ) * sizeof( TCHAR ) );
							need_free = 1;
						}

						GetWindowText( hEdit, val, cch + 1 );
						switch( dbv.type ) {
							case DBVT_BYTE:
								bChanged = ( BYTE )_tcstoul( val, NULL, 10 ) != dbv.bVal;
								break;
							case DBVT_WORD:
								bChanged = ( WORD )_tcstoul( val, NULL, 10 ) != dbv.wVal;
								break;
							case DBVT_DWORD:
								bChanged = ( DWORD )_tcstoul( val, NULL, 10 ) != dbv.dVal;
								break;
							case DBVT_TCHAR:
								bChanged = mir_tcscmp( val, dbv.ptszVal );
								break;
						}

						if( need_free ) {
							mir_free( val );
						}
					}

					DB::Variant::Free( &dbv );
					
					// update the infostructure and redraw edit control if something changed
					if( bChanged ) {
						SendMessage( GetParent( hDlg ), PSM_CHANGED, 0, 0 );
						
						// The custom text was deleted from the edit, so display the protocol based default text.
						// The flags are set by RichEdit_SetValue, but changed flag must be removed to make it work ok.
						if( ( peCtrl->wFlags & CTRLF_HASCUSTOM ) && !cch ) {
							peCtrl->wFlags &= ~CTRLF_CHANGED;
							Edit_SetValue( hDlg, idEdit, hContact, NULL, szBaseProto, szSetting );
						}
						// set the have custom setting flag
						else {
							if( hContact ) peCtrl->wFlags |= CTRLF_HASCUSTOM;
						}
						peCtrl->wFlags |= CTRLF_CHANGED;
						InvalidateRect( hEdit, NULL, TRUE );
}	}	}	}	}	}

/**
 * name:	Edit_Destroy
 * desc:	destroys info structure associated with an edit control
 * param:	hDlg	- owning propertysheetpage dialog
 *			idEdit	- control identifier for the editbox
 *
 * return	nothing
 **/
VOID Edit_Destroy( HWND hDlg, INT idEdit )
{
	HWND hEdit = GetDlgItem( hDlg, idEdit );
	LPECTRL peCtrl;

	if( hEdit && PtrIsValid( peCtrl = ( LPECTRL )GetUserData( hEdit ) ) ) {
		mir_free( peCtrl );	
	}
}

/**
 * name:	Edit_OpenUrl
 * desc:	opens the url given in a editbox in the users default browser
 * param:	hDlg	- handle to propertypage
 *			idEdit	- control identifier for edit control
 **/
VOID Edit_OpenUrl( HWND hDlg, INT idEdit )
{
	HWND hEdit = GetDlgItem( hDlg, idEdit );
	INT lenUrl = 1 + Edit_GetTextLength( hEdit );
	LPSTR szUrl;
	
	if( lenUrl > 0 && ( szUrl = ( LPSTR )mir_alloc( 7 + lenUrl ) ) ) {
		if( GetWindowTextA( hEdit, szUrl, lenUrl ) > 0 )
			CallService( MS_UTILS_OPENURL, 1, ( LPARAM )szUrl );

		mir_free(szUrl);
	}
}

LRESULT Edit_LinkNotificationHandler( HWND hDlg, ENLINK* lnk )
{
	switch( lnk->msg ) {
		case WM_SETCURSOR:
			SetCursor( LoadCursor( NULL, IDC_HAND ) );
			SetWindowLong( hDlg, DWL_MSGRESULT, TRUE );
			return TRUE;

		case WM_LBUTTONUP: {
			TEXTRANGE	tr;
			LPSTR lpstrUrl;

			// do not call function if user selected some chars of the url string
			SendMessage( lnk->nmhdr.hwndFrom, EM_EXGETSEL, NULL, ( LPARAM ) &tr.chrg );
			if( tr.chrg.cpMax != tr.chrg.cpMin )
				break;
			
			// retrieve the url string
			tr.chrg = lnk->chrg;
			tr.lpstrText = ( LPTSTR )mir_alloc( (tr.chrg.cpMax - tr.chrg.cpMin + 1)*sizeof(TCHAR) );
			if( !tr.lpstrText )
				break;

			if(SendMessage( lnk->nmhdr.hwndFrom, EM_GETTEXTRANGE, NULL, ( LPARAM )&tr ) <= 0 ){
				mir_free(tr.lpstrText);
				break;
			}

			#if defined (_UNICODE)
				lpstrUrl = mir_u2a (tr.lpstrText);
			#else
				lpstrUrl = tr.lpstrText;
			#endif			

			CallService( MS_UTILS_OPENURL, 1, ( LPARAM )lpstrUrl );
			mir_free(lpstrUrl);
			mir_free(tr.lpstrText);
		}
	}
	return FALSE;
}


/**
 * name:	RichEdit_SetValue
 * desc:	read a setting from database and set its value to the edit control
 * param:	hDlg	  - owning dialog box of edit control
 *				idEdit	  - edit controls identifier
 *				hContact  - handle to get setting from
 *				szModule  - module or NULL for base protocol to get the setting from
 *				szSetting - the setting to read
 *
 * return:	state of edit control ( changed or unchanged )
 **/
BYTE RichEdit_SetValue( HWND hDlg, INT idEdit, HANDLE hContact, LPCSTR szModule, LPCSTR szBaseProto, LPCSTR szSetting )
{
	HWND			hEdit  = GetDlgItem( hDlg, idEdit );
	LPECTRL		peCtrl = Edit_Init( hContact, hEdit );

	if( peCtrl ) {
		DBVARIANT dbv;

		if( peCtrl->wFlags & CTRLF_CHANGED ) 
			return 1;

		peCtrl->wFlags &= ~( CTRLF_HASCUSTOM|CTRLF_HASPROTO|CTRLF_HASMETA );

		if( !DB::Setting::GetTString( hContact, szModule, szSetting, &dbv ) ) {
			peCtrl->wFlags |= CTRLF_HASCUSTOM;
		}
		else if( !DB::Setting::GetTString( hContact, szBaseProto, szSetting, &dbv ) ) {
			peCtrl->wFlags |= CTRLF_HASPROTO;
		}

		EnableWindow( hEdit, 
			!hContact ||
			( peCtrl->wFlags & CTRLF_HASCUSTOM ) || 
			!( peCtrl->wFlags & ( CTRLF_HASPROTO|CTRLF_HASMETA ) ) ||
			!DB::Setting::GetByte( SET_PROPSHEET_PCBIREADONLY, 0 ) );

		if( peCtrl->wFlags & ( CTRLF_HASCUSTOM|CTRLF_HASPROTO ) ) {
			SetWindowText( hEdit, dbv.ptszVal );
			DB::Variant::Free( &dbv );
		}
		else
			SetWindowText( hEdit, _T( "" ) );

		// changed flag may have been set by some message handler, so delete it
		peCtrl->wFlags &= ~CTRLF_CHANGED;
	}
	return 0;
}

/**
 * name:	RichEdit_WriteValue
 * desc:	get value from edit control and write a setting to database
 * param:	hDlg				- owning dialog box of edit control
 *				idEdit			- edit controls identifier
 *				hContact		- handle to get setting from
 *				szModule		- module or NULL for base protocol to get the setting from
 *				szBaseProto - basic protocol for user
 *				szSetting		- the setting to read
 *
 * return 1 on failure 0 on success
 **/
VOID RichEdit_WriteValue( HWND hDlg, INT idEdit, HANDLE hContact, LPCSTR szModule, LPCSTR szBaseProto, LPCSTR szSetting )
{
	HWND hEdit = GetDlgItem( hDlg, idEdit );
	if( hEdit ) {

		LPECTRL peCtrl = ( LPECTRL )GetUserData( hEdit );
		if( PtrIsValid( peCtrl ) && peCtrl->nType == CTRL_EDIT ) {
	
			if( peCtrl->wFlags & CTRLF_CHANGED ) {
				DWORD cch = GetWindowTextLength( hEdit );
	
				if( !hContact ) szModule = szBaseProto;

				if( cch > 0 && ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ) {
					BOOLEAN		need_free = 0;
					LPTSTR		val;
				
					__try {
						val = ( LPTSTR )alloca( ( cch + 1 ) * sizeof( TCHAR ) );
					}
					__except(GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION ? 
								 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
						val = ( LPTSTR )mir_alloc( ( cch + 1 ) * sizeof( TCHAR ) );
						need_free = 1;
					}

					if( GetWindowText( hEdit, val, cch + 1 ) > 0 ) {
						DB::Setting::WriteTString( hContact, szModule, szSetting, val );
						if( !hContact ) {
							peCtrl->wFlags &= ~CTRLF_HASCUSTOM;
							peCtrl->wFlags |= CTRLF_HASPROTO;
						}
					}
					if( need_free ) {
						mir_free( val );
					}
				}
				else {
					DB::Setting::Delete( hContact, szModule, szSetting );
					peCtrl->wFlags &= ~CTRLF_HASCUSTOM;
				}			
				peCtrl->wFlags &= ~CTRLF_CHANGED;
				InvalidateRect( hEdit, NULL, TRUE );
}	}	}	}

/**
 * name:	RichEdit_Changed
 * desc:	set changed flag for edit control and current propertysheetpage
 * param:	hDlg		- owning propertysheetpage dialog
 *				idEdit	- control identifier for the editbox
 *
 * return	nothing
 **/
VOID RichEdit_Changed( HWND hDlg, INT idEdit, LPCSTR szModule, LPCSTR szSetting )
{
	// dialog is locked, or invalid protocol? return
	if( !PspIsLocked( hDlg ) ) {

		HWND hEdit = GetDlgItem( hDlg, idEdit );
		if( hEdit != NULL ) {
			
			LPECTRL peCtrl = ( LPECTRL )GetUserData( hEdit );
			if( PtrIsValid( peCtrl ) && peCtrl->nType == CTRL_EDIT ) {
				HANDLE		hContact;
				INT				cch = GetWindowTextLength( hEdit );
				
				if( !PSGetContact( hDlg, hContact ) )
					hContact = NULL;

				if( !( peCtrl->wFlags & CTRLF_CHANGED ) || ( hContact && cch == 0 && ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ) ) {
					LPCSTR		szBaseProto;
					DBVARIANT dbv;
					INT				rc;
					BOOLEAN		bChanged = FALSE;
					
					if( !PSGetBaseProto( hDlg, szBaseProto ) )
						szBaseProto = NULL;
				
					// read value from db
					rc = ( peCtrl->wFlags & CTRLF_HASCUSTOM ) ? DB::Setting::GetTString( hContact, szModule, szSetting, &dbv ) : 1;
					if( rc ) rc = DB::Setting::GetTString( hContact, szBaseProto, szSetting, &dbv );

					if( ( rc || dbv.type == DBVT_DELETED ) && cch > 0 || cch != mir_tcslen( dbv.ptszVal ) ) {
						bChanged = TRUE;
					}
					else {
						BOOLEAN		need_free = 0;
						LPTSTR		val;
					
						__try {
							val = ( LPTSTR )alloca( ( cch + 1 ) * sizeof( TCHAR ) );
						}
						__except(GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION ? 
								 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
							val = ( LPTSTR )mir_alloc( ( cch + 1 ) * sizeof( TCHAR ) );
							need_free = 1;
						}

						bChanged = GetWindowText( hEdit, val, cch + 1 ) > 0 && mir_tcscmp( val, dbv.ptszVal );

						if( need_free ) {
							mir_free( val );
						}
					}
					DB::Variant::Free( &dbv );
					
					// update the infostructure and redraw edit control if something changed
					if( bChanged ) {
						SendMessage( GetParent( hDlg ), PSM_CHANGED, 0, 0 );
						
						// The custom text was deleted from the edit, so display the protocol based default text.
						// The flags are set by RichEdit_SetValue, but changed flag must be removed to make it work ok.
						if( ( peCtrl->wFlags & CTRLF_HASCUSTOM ) && !cch ) {
							peCtrl->wFlags &= ~CTRLF_CHANGED;
							RichEdit_SetValue( hDlg, idEdit, hContact, NULL, szBaseProto, szSetting );
						}
						// set the have custom setting flag
						else {
							if( hContact ) peCtrl->wFlags |= CTRLF_HASCUSTOM;
						}
						peCtrl->wFlags |= CTRLF_CHANGED;
						InvalidateRect( hEdit, NULL, TRUE );
}	}	}	}	}	}

